import { useCallback, useEffect } from "react";
import { useState } from "react";
import { List } from "./list";
import { SearchPanel } from "./search-panel";
import qs from "query-string";
import _ from "lodash";
import { usePageTitle } from "hook/usePageTitle";

const baseUrl = process.env.REACT_APP_API_URL;

// 1 你真的知道闭包吗？
function TestFunctionComponent() {
  let num = 0;

  function effect() {
    num++;
    const msg = `第${num}条消息`;
    return () => {
      console.log(num);
      console.log(msg);
    };
  }

  return effect;
}

const effect = TestFunctionComponent();

const unmount = effect();

// 模拟react组件的更新时，会重新执行useEffect函数。
effect();
effect();
effect();

// num和msg分别是什么呢？如果是答案是4和`你好呀1`，那么恭喜你回答正确！
unmount();

export function ProjectList(props: any) {
  // 搜索参数
  const [searchParam, setSearchParam] = useState({
    keyword: "",
    personId: "",
  });

  // 负责人列表
  const [personList, setPersonList] = useState<{ id: string; name: string }[]>(
    []
  );
  useEffect(() => {
    //
    fetch(`${baseUrl}/personList`).then(async (res) => {
      if (res.ok) {
        // @ts-ignore
        setPersonList([...personList, ...(await res.json())]);
      }
    });
  }, []);

  // // 项目列表
  const [projectList, setProjectList] = useState([]);
  useEffect(() => {
    //
    fetch(`${baseUrl}/projectList`).then(async (res) => {
      if (res.ok) {
        setProjectList(await res.json());
      }
    });
  }, []);

  // 搜索延迟方法
  const delaySearch = useCallback(
    _.debounce((searchParam: { keyword: string; personId: string }) => {
      const query = qs.stringify(
        {
          name: searchParam.keyword,
          personId: searchParam.personId,
        },
        { skipEmptyString: true, skipNull: true }
      );
      //
      fetch(`${baseUrl}/projectList?${query}`).then(async (res) => {
        if (res.ok) {
          // setProjectList(await res.json())
        }
      });
    }, 500),
    []
  );

  // 搜索参数发生变化，会筛选项目列表
  useEffect(() => {
    delaySearch(searchParam);
  }, [searchParam]);

  const [count, setCount] = useState(0);
  usePageTitle(count + " title");

  /**
    useEffect钩子

    只传第一个参数

      无返回函数 

      有返回函数

    传两个参数，第一个是回调函数（无返回函数、有返回函数），第二个是数组（ 空数组、有值数组）

  */

  // 只传第一个回调参数，不返回函数
  // 执行1+n次（1代表第一次挂载，n代表组件更新的次数）
  useEffect(() => {
    // count每次都会输出0
    console.log("打印1+" + count + "次");
  });
  // 应用场景: 不传第二个参数，也就说明每次组件更新时 不用比较更新前后的值是否相同，直接执行传入useEffect的回调参数。 这种写法应用场景比较少，不过需要知道其表现。

  // 执行n+1次（n代表组件更新的次数，1代表组件卸载了）
  useEffect(() => {
    return () => {
      // count每次都会输出0
      console.log("打印1+n次");
    };
  });
  // 应用场景: 较少

  /**
    如果加了第二个参数数组，
      也就意味着每次组件更新时，都要比较前后的值是否相同。只有不同时才会执行传入useEffect的回调参数。
  */

  // 传两个参，第二个参为空数组，第一个参数不返回函数
  // 执行1次。
  // 如果第二个参数是空数组，意味着前后值的肯定是一样的，只会在组件挂载时执行一次，之后无论组件更新多少次，都不会触发。
  useEffect(() => {
    console.log("参数二 是空数组，只会在挂载时执行一次");
  }, []);
  // 应用场景: 在组件挂载后发请求，将数据渲染到页面上。

  // 传两个参，第二个参为空数组，第一个参数返回函数
  // 只会在组件卸载时打印一次。
  useEffect(() => {
    return () => {
      console.log(count, "这里一定是0，无论count加了多少");
    };
  }, []);
  // 应用场景: 组件卸载（更新不会触发）时发一个请求。

  // 传两个参，第二个参不为空数组，第一个参数不返回函数
  // 执行1+n次。
  // 第二个参数有值，如果组件更新时传入数组前后的值有一个不相同，回调才会执行。基础数据比较值，引用数据会进行完全比较。
  useEffect(() => {
    console.log("参数二 是有值数组，会执行1 + " + count + " 次");
  }, [count]);
  // 应用场景: 监视响应式变化，触发回调

  // 传两个参，第二个参不为空数组，第一个参数返回函数
  // 打印n+1次。
  useEffect(() => {
    return () => {
      console.log(
        count,
        "如果是更新，打印的是更新前的值（因为更新前要先卸载）。如果是卸载，获取到的是最新的值"
      );
    };
  }, [count]); // 每当count变化，回调都会重新执行一遍，返回的函数也就形成了新的闭包
  // 应用场景: 还没想到

  return (
    <>
      <SearchPanel
        searchParam={searchParam}
        setSearchParam={setSearchParam}
        personList={personList}
      ></SearchPanel>
      <List projectList={projectList} personList={personList}></List>
      <button onClick={props.logout}>退出登录</button>
      <button onClick={() => setCount(count + 1)}>加1</button>
      <button>{count}</button>
    </>
  );
}
